<?php
/**
* A php class for mysql database query
*
* mysql class is design to incapsulate the query of mysql database.
* some public functions a convenient for data query, and reduce code
*
* @package mysql
* @author nonsenser
* @version 1.0
* @copyright nonsenser@163.com
*/
class mysql{
	// properties
	/**
	* database connection for rest use.
	* @var object
	*/
	var $conn = 0;
	/**
	* sql query string
	* @var string
	*/
	var $sql;
	/**
	* a query counter
	* @var integer
	*/
	protected static $querycount = 0;
	
	// methods
	/**
	* connect to the database using given parameters
	* @param string $dbhost database server host address
	* @param string $dbuser username used to connect to the database server
	* @param string $dbpass password for early username
	* @param string $dbname database name which is used
	* @param boolean $pconnect default false, whether to use persistant connection
	* @param string $charset default utf8, charset used in query results
	*/
	function connect($dbhost='localhost', $dbuser, $dbpass, $dbname, $pconnect=0, $charset='utf8'){
		$this->conn = $this->pconnect==0 ? @mysql_connect($dbhost, $dbuser, $dbpass, true) : @mysql_pconnect($dbhost, $dbuser, $dbpass);
		if (!($this->conn)) $this->halt(mysql_errno());
		mysql_errno($this->conn)!=0 && $this->halt("Connect($pconnect) to MySQL failed");
		$serverinfo = mysql_get_server_info($this->conn);
		if ($serverinfo > '4.1' && $charset) {
			mysql_query("SET character_set_connection=$charset, character_set_results=$charset, character_set_client=binary", $this->conn);
		}
		if ($serverinfo > '5.0') {
			mysql_query("SET sql_mode=''", $this->conn);
		}
		if ($dbname && !@mysql_select_db($dbname,$this->conn)) {
			$this->halt('Cannot use database');
		}
	}
	
	/**
	* select a specific database which our query data come from
	* @param string $dbname database name
	*/
	function select_db($dbname){
		if (!@mysql_select_db($dbname, $this->conn)) {
			$this->halt('Cannot use database');
		}
	}
	
	/**
	* execute a sql query
	* @param string $sql sql command string
	* @param constant string $type type of the query, buffered or unbuffered, buffered default
	* @return object a query object
	*/
	function query($sql, $type='')
	{
		$func = $type == 'UNBUFFERED' && @function_exists('mysql_unbuffered_query') ?
			'mysql_unbuffered_query' : 'mysql_query';
		if(!($query = @$func($sql , $this->conn)) && $type != 'SILENT')
		{
			$this->halt('MySQL query error ', $sql);
			return false;
		}
		self::$querycount++;
		return $query;
	}
	
	/**
	* fetch an array with the given query object
	* @param object $query a query object return by query method
	* @param constant $result_type used to determine whether return only the result indexed by number or only by key string both
	* @return array an array which contains the total result of the query
	*/
	function fetch_array($query, $result_type = MYSQL_ASSOC) {
		return mysql_fetch_array($query, $result_type);
	}
	
	/**
	* fecth a single array with the given query object
	* @param object $query a query object return by query method
	* @return array a one dimension array of the result, move the recordset pointer to next record automatically, return null if not any more 
	*/
	function fetch_row($query) {
		$query = mysql_fetch_row($query);
		return $query;
	}

	/**
	* execute a select sql query with the given sql command string and make the keyfield as a key index
	* @param string $sql sql command string
	* @param string $keyfield field label used to constuct a new key indexed array
	* @return array an array of the selected results
	*/
	function select($sql, $keyfield='')
	{
		$array = array();
		$result = $this->query($sql);
		while($r = $this->fetch_array($result))
		{
			if($keyfield)
			{
				$key = $r[$keyfield];
				$array[$key] = $r;
			}
			else
			{
				$array[] = $r;
			}
		}
		$this->free_result($result);
		return $array;
	}

	/**
	* insert a record into the table
	* @param string $tablename name of the table into which the data was inserted.
	* @param array $array key indexed data array
	*/
	function insert($tablename, $array)
	{
		$this->check_fields($tablename, $array);
		return $this->query("INSERT INTO `$tablename`(`".implode('`,`', array_keys($array))."`) VALUES('".implode("','", $array)."')");
	}

	/**
	* update a specific item in the given table
	* @param string $tablename name of the table 
	* @param array $array key indexed data array
	* @param string $where the filter string which should follow the WHERE keyword in the sql command string
	*/
	function update($tablename, $array, $where = '')
	{
		$this->check_fields($tablename, $array);
		if($where)
		{
			$sql = '';
			foreach($array as $k=>$v)
			{
				$sql .= ", `$k`='$v'";
			}
			$sql = substr($sql, 1);
			$sql = "UPDATE `$tablename` SET $sql WHERE $where";
		}
		else
		{
			$sql = "REPLACE INTO `$tablename`(`".implode('`,`', array_keys($array))."`) VALUES('".implode("','", $array)."')";
		}
		return $this->query($sql);
	}
	
	/**
	* fecth a single array with the given query command string
	* @param object $query a query command string
	* @return array a one dimension array of the result, move the recordset pointer to next record automatically, return null if not any more 
	*/
	function fetch_one_array($sql) {
		$result = $this->query($sql);
		$record = $this->fetch_array($result);
		$this->free_result($result);
		return $record;
	}

	/**
	* return the number of rows the given sql query will return
	* @param object $query a query command string
	* @return integer number of rows
	*/
	function num_rows($sql) {
		$query = mysql_query($sql);
		$query = mysql_num_rows($query);
		return $query;
	}

	/**
	* return the number of fields the given sql query will return
	* @param object $query a query command string
	* @return integer number of fields
	*/
	function num_fields($sql) {
		$query = mysql_query($sql);
		return mysql_num_fields($query);
	}
	
	/**
	* get the specific field with the given query object
	* @param object $query the query object
	* @param integer $row the specific row which should be returned
	*/
	function result($query, $row) {
		$result = @mysql_result($query, $row);
		return $result;
	}
	
	/**
	* free the memory related to the resouce id query
	*/
	function free_result($query) {
		$query = mysql_free_result($query);
		return $query;
	}

	/**
	* get the version of the database server program
	*/
	function version() {
		return mysql_get_server_info();
	}

	/**
	* close connection to the database
	*/
	function close() {
		return mysql_close();
	}
	
	/**
	* get the error description string
	* @return string detail information of the last error
	*/
	function geterrdesc() {
		return mysql_error();
	}
	
	/**
	* get the error number
	* @return integer number of the last error
	*/
	function geterrno() {
		return intval(mysql_errno());
	}

	/**
	* get the inserted id by the last INSERT query
	* @return integer inserted id of the last INSERT query
	*/
	function insert_id() {
		$id = mysql_insert_id();
		return $id;
	}
	
	/**
	* insert the error into the error log file and print out a friendly error message
	* @param string $msg user specific error message
	* @param string $sql sql query string in which error occurred
	* @global string DBERROR_LOG_PATH database query error log file path
	*/
	function halt($msg, $sql=''){
		$timestamp = strftime('%B %d,%Y,%H:%M %p', time());
		if ($sql && file_exists(DBERROR_LOG_PATH)) {
			$fp = fopen(DBERROR_LOG_PATH, 'a');
			fwrite($fp, "$timestamp\t".basename($_SERVER['SCRIPT_NAME'])."\t".htmlspecialchars($this->geterrdesc())."\t".str_replace(array("\r", "\n", "\t"), array(' ', ' ', ' '), trim(htmlspecialchars($sql)))."\n");
			fclose($fp);
		}

		$message = "<html>\n<head>\n";
		$message .= "<meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\">\n";
		$message .= "<style type=\"text/css\">\n";
		$message .=  "body,p,pre {\n";
		$message .=  "font:12px Verdana;\n";
		$message .=  "}\n";
		$message .=  "</style>\n";
		$message .= "</head>\n";
		$message .= "<body bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#006699\" vlink=\"#5493B4\">\n";

		$message .= "<p>数据库出错:</p><pre><b>".htmlspecialchars($msg)."</b></pre>\n";
		$message .= "<b>Mysql error description</b>: ".htmlspecialchars($this->geterrdesc())."\n<br />";
		$message .= "<b>Mysql error number</b>: ".$this->geterrno()."\n<br />";
		$message .= "<b>Date</b>: ".date("Y-m-d @ H:i")."\n<br />";
		$message .= "<b>Script</b>: http://".$_SERVER['HTTP_HOST'].getenv("REQUEST_URI")."\n<br />";

		$message .= "</body>\n</html>";
		echo $message;
		exit;
	}
}

?>